1 What is Cancer?


1.2 Replication Crisis Excel Version


2 RStudio ile proje oluştur


3 R Notebook

3.1 R Notebook dökümanı oluşturma


3.2 R Notebook’tan html, pdf ve word oluşturma


3.3 RNotebook vs RMarkdown

https://youtu.be/zNzZ1PfUDNk


4 R Markdown

4.1 Hem kendi kodları hem de html kodları yazılabilir

https://rmarkdown.rstudio.com

What is R Markdown? from RStudio, Inc. on Vimeo.


4.2 R Markdown: The Definitive Guide

https://bookdown.org/yihui/rmarkdown/


4.3 R Markdown syntax

https://gist.github.com/MinhasKamal/7fdebb7c424d23149140


4.4 Remedy Package


4.4.1 Remedy


4.6 Render Markdown via code

inside R

markdown::markdownToHTML('markdown_example.md', 
'markdown_example.html')

command line

R -e "markdown::markdownToHTML('markdown_example.md',
'markdown_example.html')"

4.7 pandoc Rstudio integration

command line

export PATH=$PATH:/Applications/RStudio.app/Contents/MacOS/pandoc
R -e "rmarkdown::render('markdown_example.md')"

5 RMarkdown chunk içinde R kodlarını çalıştırma

{r, results='asis'}
 iris %>%
  tibble::as_tibble() %>%
  details::details(summary = 'tibble')

6 Metin arasında R kodlarını çalıştırma


7 Chunk Options

7.1 Global Options

{r global_options, include=FALSE}
knitr::opts_chunk$set(fig.width = 12,
                      fig.height = 8,
                      fig.path = 'Figs/',
                      echo = FALSE,
                      warning = FALSE,
                      message = FALSE,
                      error = FALSE,
                      eval = TRUE,
                      tidy = TRUE,
                      comment = NA)

7.2 Other Code Languages


8 R Markdown kod örneği

{r}
data("cancer")
cancer
foreign::write.foreign(df = cancer,
                        datafile = "data/cancer.sav",
                        codefile = "data/cancer.spo",
                        package = "SPSS"
                        )

9 R Markdown Paket Çağırma 📦

{r}
suppressPackageStartupMessages(library("tidyverse"))
suppressPackageStartupMessages(library("survival"))

9.1 Sık kullandığım paketler 📦

{tidyverse} {tidylog}

{lubridate} {janitor}

{readxl} {foreign}

{summarytools} {ggstatsplot} {tangram} {finalfit} {psycho} {jmv}

{survival} {survminer}

{report} {kableExtra}


10 R Markdown Veri Yükleme SPSS


11 R Markdown Veri Yükleme Excel


12 Veri Görüntüleme

{r}
View(mydata)
glimpse(mydata)

13 Veri Düzenleme

{r}
mydata <- janitor::clean_names(mydata)
{r}
mydata$sontarih <- janitor::excel_numeric_to_date(
  as.numeric(mydata$olum_tarihi)
  )

14 Recode

{r}
mydata$Outcome <- "Dead"
mydata$Outcome[mydata$olum_tarihi == "yok"] <- "Alive"
{r}
## Recoding mydata$cinsiyet into mydata$Cinsiyet
mydata$Cinsiyet <- recode(mydata$cinsiyet,
               "K" = "Kadin",
               "E" = "Erkek")
mydata$Cinsiyet <- factor(mydata$Cinsiyet)

15 Recode regular expression

{r recode TNM stage}
#pT2N0Mx -> 2
mydata$Tstage <- stringr::str_match(
  mydata$patolojik_evre, 
  paste('(.+)', "N", sep=''))[,2]
)

16 Recode regular expression case_when

{r recode TNM2}
mydata <- mydata %>% 
    mutate(
        T_stage = case_when(
            grepl(pattern = "T1", x = .$Tstage) == TRUE ~ "T1",
            grepl(pattern = "T2", x = .$Tstage) == TRUE ~ "T2",
            grepl(pattern = "T3", x = .$Tstage) == TRUE ~ "T3",
            grepl(pattern = "T4", x = .$Tstage) == TRUE ~ "T4",
            TRUE ~ "Tx"
        )
    )

17 Recode regular expression case_when

{r}
mydata <- mydata %>% 
    mutate(
TumorPDL1gr1 = case_when(
        t_pdl1 < 1 ~ "kucuk1",
        t_pdl1 >= 1 ~ "buyukesit1"
    )
    )

18 R Markdown Tanımlayıcı İstatistikler

{r}
library(summarytools)
view(dfSummary(colon_s))

A beginner kit for #rstats The Landscape of R Packages for Automated Exploratory Data Analysis https://journal.r-project.org/archive/2019/RJ-2019-033/

@article{RJ-2019-033, author = {Mateusz Staniak and Przemysław Biecek}, title = {{The Landscape of R Packages for Automated Exploratory Data Analysis}}, year = {2019}, journal = {{The R Journal}}, doi = {10.32614/RJ-2019-033}, url = {https://journal.r-project.org/archive/2019/RJ-2019-033/index.html} }


18.1 Table One

{r, results='asis'}
# cat(names(mydata), sep = " + \n")
library(arsenal)
tab1 <- tableby(~ Cinsiyet + 
Yas + 
TumorYerlesimi
                ,
                data = mydata)
summary(tab1)

18.3 Kategorik Veriler

{r}
mydata %>% 
  janitor::tabyl(Categorical) %>%
  adorn_pct_formatting(rounding = 'half up',
                       digits = 1) %>%
  knitr::kable()
{r crosstable}
mydata %>%
    summary_factorlist(dependent = dependent, 
                       explanatory = explanatory,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE) -> table
knitr::kable(table, row.names = FALSE, align = c('l', 'l', 'r', 'r', 'r'))

18.4 Kategorik Veriler için Grafikler

{r ggstatplot, layout='l-page'}
mydata %>% 
    ggstatsplot::ggbarstats(data = .,
                            main = Categorical_variable,
                            condition =  dependent_variable
                            )

18.5 Continious Variables

{r}
mydata %>% 
jmv::descriptives(
    data = .,
    vars = c(yas),
    hist = TRUE,
    dens = TRUE,
    box = TRUE,
    violin = TRUE,
    dot = TRUE,
    mode = TRUE,
    sd = TRUE,
    variance = TRUE,
    skew = TRUE,
    kurt = TRUE,
    quart = TRUE)

19 R Markdown örneği Çapraz Tablolar

{r crosstable}
library(finalfit)
mydata %>%
    summary_factorlist(dependent = dependent, 
                       explanatory = explanatory,
                       column = TRUE,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE,
                       na_include=FALSE
                       # catTest = catTestfisher
                       ) -> table
knitr::kable(table,
             row.names = FALSE,
             align = c('l', 'l', 'r', 'r', 'r'))

20 R Markdown örneği Sağkalım

20.1 Sağkalım için veriyi düzenleme

{r define survival time}
mydata$int <- lubridate::interval(
  lubridate::ymd(mydata$CerrahiTarih),
  lubridate::ymd(mydata$SonTarih)
  )
mydata$OverallTime <- lubridate::time_length(mydata$int, "month")
mydata$OverallTime <- round(mydata$OverallTime, digits = 1)
{r}
## Recoding mydata$Outcome into mydata$Outcome2
mydata$Outcome2 <- recode(mydata$Outcome,
               "Alive" = "0",
               "Dead" = "1")
mydata$Outcome2 <- as.numeric(mydata$Outcome2)

20.2 Kaplan-Meier

{r Kaplan-Meier}
mydata %>%
  finalfit::surv_plot(dependent,
                      explanatory,
                      xlab='Time (months)',
                      pval=TRUE,
                      legend = 'none',
                      break.time.by = 12,
                      xlim = c(0,60),
                      legend.labs = c('a','b')
)

20.3 Sağkalım Tabloları

{r}
km_fit <- survfit(dependent ~ explanatory,
                  data = mydata)
km_fit
{r, eval=FALSE, include=FALSE}
library(survival)
km <- with(mydata, Surv(OverallTime, Outcome2))
# head(km,80)
# plot(km)
{r 1-3-5-yr}
summary(km_fit, times = c(12,36,60))

20.4 Pairwise comparison

{r}
survminer::pairwise_survdiff(formula = Surv(time, Outcome) ~ Group, 
                             data = mydata,
                             p.adjust.method = "BH")

20.5 Multivariate Analysis Survival

{r Multivariate Analysis, eval=FALSE, include=FALSE}
library(finalfit)
library(survival)
explanatoryMultivariate <- explanatoryKM
dependentMultivariate <- dependentKM
mydata %>%
  finalfit(dependentMultivariate, explanatoryMultivariate) -> tMultivariate
knitr::kable(tMultivariate, row.names=FALSE, align=c("l", "l", "r", "r", "r", "r"))

21 jamovi

21.1 jamovi ve R entegrasyonu

Rj Editor – Analyse your data with R in jamovi


21.2 {jmv} paket kodları

jamovi syntax mode


22 Güncellemeler olunca kodlar çalışacak mı?


22.1 Paket Kütüphaneleri

  • packrat / renv

https://environments.rstudio.com


22.2 Docker

  • docker

22.2.1 The Rocker Project

Docker Containers for the R Environment

docker run --rm -ti rocker/r-base

Or get started with an RStudio® instance:

docker run -e PASSWORD=yourpassword --rm -p 8787:8787 rocker/rstudio

and point your browser to localhost:8787 Log in with user/password rstudio/yourpassword


Managing containers


22.3 Yeni R sürümleri

  • RSwitch

https://rud.is/rswitch/

  • Using RSwitch

https://rud.is/rswitch/guide/

: scale 30%


23 Yedeklemeyi nasıl yapacağız

23.1 Projeyi düzgün organize edin

  • pdf
  • R
  • images
  • bib
{r load library}
source(file = here::here("R", "loadLibrary.R"))

23.2 Save Final Data

{r}
saved data after analysis to `mydata.xlsx`.

save.image(file = here::here("data", "mydata_work_space.RData"))

readr::write_rds(x = mydata, path = here::here("data", "mydata_afteranalysis.rds"))

saveRDS(object = mydata, file = here::here("data", "mydata.rds"))

writexl::write_xlsx(mydata, here::here("data", "mydata.xlsx"))

paste0(rownames(file.info(here::here("data", "mydata.xlsx"))), " : ", file.info(here::here("data", "mydata.xlsx"))$ctime)

23.3 GitHub Yedekleme


24 Her dökümanın sonuna kullandığınız kütüphaneler için atıf yazdırabilirsiniz

{r}
citation()

24.1 Libraries Used

citation()

24.2 Bu oturuma spesifik kullanılan paketler


24.3 Tek tek paket atıfları

{r library citations}
citation("tidyverse")
citation("readxl")
citation("janitor")
citation("report")
citation("finalfit")
citation("ggstatplot")

24.4 Jamovi ve R için atıf örneği


25 Her dökümanın sonuna oturum detaylarınızı yazdırabilirsiniz

{r session info, echo=TRUE}
sessionInfo()

25.1 Session Info

sessionInfo()

26 Sonraki Konular

  • RStudio ile GitHub kullanımı

29 Geri Bildirim



LS0tCnRpdGxlOiBXaGF0IGlzIENhbmNlcj8KYXV0aG9yOiAiW1NlcmRhciBCYWxjxLEsIE1ELCBQYXRob2xvZ2lzdF0oaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvLykiCmluc3RpdHV0ZTogIltzZXJkYXJiYWxjaS5jb21dKGh0dHBzOi8vd3d3LnNlcmRhcmJhbGNpLmNvbSkgW3BhdG9sb2ppbm90bGFyaS5jb21dKGh0dHBzOi8vd3d3LnBhdG9sb2ppbm90bGFyaS5jb20pIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCkpYCIKb3V0cHV0OgogIHJldmVhbGpzOjpyZXZlYWxqc19wcmVzZW50YXRpb246CiAgICBrZWVwX21kOiB0cnVlCiAgICBpbmNyZW1lbnRhbDogdHJ1ZQogICAgdGhlbWU6IHNreQogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgY2VudGVyOiBmYWxzZQogICAgc21hcnQ6IHRydWUKICAgIHRyYW5zaXRpb246IGZhZGUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICBpZ193aWR0aDogNwogICAgZmlnX2hlaWdodDogNgogICAgZmlnX2NhcHRpb246IHRydWUKICAgIHJldmVhbF9vcHRpb25zOgogICAgICBzbGlkZU51bWJlcjogdHJ1ZQogICAgICBwcmV2aWV3TGlua3M6IHRydWUKICBwcmV0dHlkb2M6Omh0bWxfcHJldHR5OgogICAga2VlcF9tZDogdHJ1ZQogICAgdGhlbWU6IGxlb25pZHMKICAgIGhpZ2hsaWdodDogZ2l0aHViCiAgcm1kc2hvd2VyOjpzaG93ZXJfcHJlc2VudGF0aW9uOgogICAga2VlcF9tZDogdHJ1ZQogIGh0bWxfbm90ZWJvb2s6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBoaWdobGlnaHQ6IGthdGUKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogZmxhdGx5CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6IHllcwogIHhhcmluZ2FuOjptb29uX3JlYWRlcjoKICAgIGtlZXBfbWQ6IHRydWUKICAgIGxpYl9kaXI6IGxpYnMKICAgIG5hdHVyZToKICAgICAgYmVmb3JlSW5pdDogWyJtYWNyb3MuanMiLCAiaHR0cHM6Ly9wbGF0Zm9ybS50d2l0dGVyLmNvbS93aWRnZXRzLmpzIl0KICAgICAgaGlnaGxpZ2h0U3R5bGU6IGdpdGh1YgogICAgICBoaWdobGlnaHRMaW5lczogdHJ1ZQogICAgICBjb3VudEluY3JlbWVudGFsU2xpZGVzOiBmYWxzZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICBwZGZfZG9jdW1lbnQ6CiAgICBrZWVwX21kOiB0cnVlCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnNScKICBodG1sX2RvY3VtZW50OgogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6IHllcwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgo8IS0tIE9wZW4gYWxsIGxpbmtzIGluIG5ldyB0YWItLT4gIAo8YmFzZSB0YXJnZXQ9Il9ibGFuayIvPiAgCgoKPCEtLSBHbyB0byB3d3cuYWRkdGhpcy5jb20vZGFzaGJvYXJkIHRvIGN1c3RvbWl6ZSB5b3VyIHRvb2xzIC0tPiA8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSIvL3M3LmFkZHRoaXMuY29tL2pzLzMwMC9hZGR0aGlzX3dpZGdldC5qcyNwdWJpZD1yYS01YmMzNjkwMGE0MDUwOTBiIj4gIAo8L3NjcmlwdD4KCgoKYGBge3IgZ2xvYmFsX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDgsIGZpZy5wYXRoID0gJ0ZpZ3MvJywgZWNobyA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZXJyb3IgPSBGQUxTRSwgZXZhbCA9IFRSVUUsIHRpZHkgPSBUUlVFLCBjb21tZW50ID0gTkEsIGNhY2hlID0gVFJVRSkKYGBgCgoKCmBgYHtyIHhhcmluZ2FuLCBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojIHhhcmluZ2FuOjppbmZfbXIoKQojIHNlcnZyOjpkYWVtb25fc3RvcCgxKQpgYGAKCgoKIyBXaGF0IGlzIENhbmNlcj8KCgoKCgoKLS0tCgoKIyMgUmVwbGljYXRpb24gQ3Jpc2lzCgoKCmh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1JlcGxpY2F0aW9uX2NyaXNpcwoKCi0tLQoKIyMgUmVwbGljYXRpb24gQ3Jpc2lzIEV4Y2VsIFZlcnNpb24KCgoKCi0tLQoKIyBSU3R1ZGlvIGlsZSBwcm9qZSBvbHXFn3R1cgoKCgoKCgoKLS0tCgojIFIgTm90ZWJvb2sgIAoKIyMgUiBOb3RlYm9vayBkw7Zrw7xtYW7EsSBvbHXFn3R1cm1hIAoKCgoKLS0tCgojIyBSIE5vdGVib29rJ3RhbiBodG1sLCBwZGYgdmUgd29yZCBvbHXFn3R1cm1hICAKCgoKCgotLS0KCiMjIFJOb3RlYm9vayB2cyBSTWFya2Rvd24gIAoKPGlmcmFtZSB3aWR0aD0iNTYwIiBoZWlnaHQ9IjMxNSIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC96TnpaMVBmVUROayIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuPjwvaWZyYW1lPiAgCgpodHRwczovL3lvdXR1LmJlL3pOeloxUGZVRE5rCgoKLS0tCgojIFIgTWFya2Rvd24KCiMjIEhlbSBrZW5kaSBrb2RsYXLEsSBoZW0gZGUgaHRtbCBrb2RsYXLEsSB5YXrEsWxhYmlsaXIKCmh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tCgo8aWZyYW1lIHNyYz0iaHR0cHM6Ly9wbGF5ZXIudmltZW8uY29tL3ZpZGVvLzE3ODQ4NTQxNj9jb2xvcj00MjhiY2EmdGl0bGU9MCZieWxpbmU9MCZwb3J0cmFpdD0wIiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjQwMCIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhdXRvcGxheTsgZnVsbHNjcmVlbiIgYWxsb3dmdWxsc2NyZWVuPjwvaWZyYW1lPgo8cD48YSBocmVmPSJodHRwczovL3ZpbWVvLmNvbS8xNzg0ODU0MTYiPldoYXQgaXMgUiBNYXJrZG93bj88L2E+IGZyb20gPGEgaHJlZj0iaHR0cHM6Ly92aW1lby5jb20vcnN0dWRpb2luYyI+UlN0dWRpbywgSW5jLjwvYT4gb24gPGEgaHJlZj0iaHR0cHM6Ly92aW1lby5jb20iPlZpbWVvPC9hPi48L3A+CgotLS0KCiMjIFIgTWFya2Rvd246IFRoZSBEZWZpbml0aXZlIEd1aWRlCgpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vCgoKLS0tCgojIyBSIE1hcmtkb3duIHN5bnRheAoKaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vTWluaGFzS2FtYWwvN2ZkZWJiN2M0MjRkMjMxNDkxNDAKCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vTWluaGFzS2FtYWwvN2ZkZWJiN2M0MjRkMjMxNDkxNDAuanMiPjwvc2NyaXB0PgoKCgotLS0KCiMjIFJlbWVkeSBQYWNrYWdlICAKCls8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1RoaW5rUi1vcGVuL3JlbWVkeS9tYXN0ZXIvcmVmZXJlbmNlL2ZpZ3VyZXMvdGhpbmtyLWhleC1yZW1lZHkucG5nIiB3aWR0aD0yNTBweD5dKGh0dHBzOi8vZ2l0aHViLmNvbS9UaGlua1Itb3Blbi9yZW1lZHkpCgoKLS0tCgojIyMgUmVtZWR5ICAKCls8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1RoaW5rUi1vcGVuL3JlbWVkeS9tYXN0ZXIvcmVmZXJlbmNlL2ZpZ3VyZXMvcmVtZWR5X2V4YW1wbGUuZ2lmIiB3aWR0aD01MDBweD5dKGh0dHBzOi8vZ2l0aHViLmNvbS9UaGlua1Itb3Blbi9yZW1lZHkpCgoKLS0tCgojIyBSIE1hcmtkb3duIHBha2V0IHZlIMWfYWJsb25sYXLEsSAgCgpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vZG9jdW1lbnQtdGVtcGxhdGVzLmh0bWwKCgoKCgotLS0KCiMjIFJlbmRlciBNYXJrZG93biB2aWEgY29kZQoKKmluc2lkZSBSKgoKYGBgCm1hcmtkb3duOjptYXJrZG93blRvSFRNTCgnbWFya2Rvd25fZXhhbXBsZS5tZCcsIAonbWFya2Rvd25fZXhhbXBsZS5odG1sJykKYGBgCgoqY29tbWFuZCBsaW5lKgoKYGBgClIgLWUgIm1hcmtkb3duOjptYXJrZG93blRvSFRNTCgnbWFya2Rvd25fZXhhbXBsZS5tZCcsCidtYXJrZG93bl9leGFtcGxlLmh0bWwnKSIKYGBgCgotLS0KCgojIyBwYW5kb2MgUnN0dWRpbyBpbnRlZ3JhdGlvbgoKKmNvbW1hbmQgbGluZSoKCmBgYApleHBvcnQgUEFUSD0kUEFUSDovQXBwbGljYXRpb25zL1JTdHVkaW8uYXBwL0NvbnRlbnRzL01hY09TL3BhbmRvYwpgYGAKCgpgYGAKUiAtZSAicm1hcmtkb3duOjpyZW5kZXIoJ21hcmtkb3duX2V4YW1wbGUubWQnKSIKYGBgCgoKLS0tCgojIFJNYXJrZG93biBgY2h1bmtgIGnDp2luZGUgYFJgIGtvZGxhcsSxbsSxIMOnYWzEscWfdMSxcm1hCgoKYGBgCntyLCByZXN1bHRzPSdhc2lzJ30KIGlyaXMgJT4lCiAgdGliYmxlOjphc190aWJibGUoKSAlPiUKICBkZXRhaWxzOjpkZXRhaWxzKHN1bW1hcnkgPSAndGliYmxlJykKYGBgCgotLS0KCiMgTWV0aW4gYXJhc8SxbmRhIGBSYCBrb2RsYXLEsW7EsSDDp2FsxLHFn3TEsXJtYQoKCgoKCi0tLQoKIyBDaHVuayBPcHRpb25zCgojIyBHbG9iYWwgT3B0aW9ucwoKYGBgCntyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gOCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5wYXRoID0gJ0ZpZ3MvJywKICAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGVycm9yID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBldmFsID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIHRpZHkgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BKQpgYGAKCi0tLQoKIyMgT3RoZXIgQ29kZSBMYW5ndWFnZXMKCgpbIVtdKGh0dHBzOi8vZDMzd3VicmZraTBsNjguY2xvdWRmcm9udC5uZXQvMTYyMzQ3ZWY1YWZlMjE5ZGEyMmZiN2Q3ZDlhNTk4OWYyYzNlNWE4NS81OTMxNi9sZXNzb24taW1hZ2VzL2xhbmd1YWdlcy0xLWRlbW9zLnBuZyldKGh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2xlc3Nvbi01Lmh0bWwpCgoKLS0tCgoKIyBSIE1hcmtkb3duIGtvZCDDtnJuZcSfaSAgCgoKYGBgCntyfQpkYXRhKCJjYW5jZXIiKQpjYW5jZXIKZm9yZWlnbjo6d3JpdGUuZm9yZWlnbihkZiA9IGNhbmNlciwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YWZpbGUgPSAiZGF0YS9jYW5jZXIuc2F2IiwKICAgICAgICAgICAgICAgICAgICAgICAgY29kZWZpbGUgPSAiZGF0YS9jYW5jZXIuc3BvIiwKICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZSA9ICJTUFNTIgogICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKCi0tLQoKIyBSIE1hcmtkb3duIFBha2V0IMOHYcSfxLFybWEg8J+TpiAgICAKCgpgYGAKe3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJ0aWR5dmVyc2UiKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoInN1cnZpdmFsIikpCmBgYAoKLS0tCgojIyBTxLFrIGt1bGxhbmTEscSfxLFtIHBha2V0bGVyIPCfk6YgIAoKe3RpZHl2ZXJzZX0Ke3RpZHlsb2d9Cgp7bHVicmlkYXRlfQp7amFuaXRvcn0KCntyZWFkeGx9Cntmb3JlaWdufQoKe3N1bW1hcnl0b29sc30Ke2dnc3RhdHNwbG90fQp7dGFuZ3JhbX0Ke2ZpbmFsZml0fQp7cHN5Y2hvfQp7am12fQoKe3N1cnZpdmFsfQp7c3Vydm1pbmVyfQoKe3JlcG9ydH0Ke2thYmxlRXh0cmF9CgotLS0KCiMgUiBNYXJrZG93biBWZXJpIFnDvGtsZW1lIFNQU1MgIAoKCgoKLS0tCgojIFIgTWFya2Rvd24gVmVyaSBZw7xrbGVtZSBFeGNlbCAgCgoKCgoKCi0tLQoKIyBWZXJpIEfDtnLDvG50w7xsZW1lCgoKYGBgCntyfQpWaWV3KG15ZGF0YSkKZ2xpbXBzZShteWRhdGEpCmBgYAoKCgoKLS0tCgojIFZlcmkgRMO8emVubGVtZQoKYGBgCntyfQpteWRhdGEgPC0gamFuaXRvcjo6Y2xlYW5fbmFtZXMobXlkYXRhKQpgYGAKCmBgYAp7cn0KbXlkYXRhJHNvbnRhcmloIDwtIGphbml0b3I6OmV4Y2VsX251bWVyaWNfdG9fZGF0ZSgKICBhcy5udW1lcmljKG15ZGF0YSRvbHVtX3RhcmloaSkKICApCmBgYAoKCi0tLQoKIyBSZWNvZGUKCgpgYGAKe3J9Cm15ZGF0YSRPdXRjb21lIDwtICJEZWFkIgpteWRhdGEkT3V0Y29tZVtteWRhdGEkb2x1bV90YXJpaGkgPT0gInlvayJdIDwtICJBbGl2ZSIKYGBgCgoKYGBgCntyfQojIyBSZWNvZGluZyBteWRhdGEkY2luc2l5ZXQgaW50byBteWRhdGEkQ2luc2l5ZXQKbXlkYXRhJENpbnNpeWV0IDwtIHJlY29kZShteWRhdGEkY2luc2l5ZXQsCiAgICAgICAgICAgICAgICJLIiA9ICJLYWRpbiIsCiAgICAgICAgICAgICAgICJFIiA9ICJFcmtlayIpCm15ZGF0YSRDaW5zaXlldCA8LSBmYWN0b3IobXlkYXRhJENpbnNpeWV0KQpgYGAKCgotLS0KCiMgUmVjb2RlIHJlZ3VsYXIgZXhwcmVzc2lvbgoKCmBgYAp7ciByZWNvZGUgVE5NIHN0YWdlfQojcFQyTjBNeCAtPiAyCm15ZGF0YSRUc3RhZ2UgPC0gc3RyaW5ncjo6c3RyX21hdGNoKAogIG15ZGF0YSRwYXRvbG9qaWtfZXZyZSwgCiAgcGFzdGUoJyguKyknLCAiTiIsIHNlcD0nJykpWywyXQopCmBgYAoKCi0tLQoKIyBSZWNvZGUgcmVndWxhciBleHByZXNzaW9uIGNhc2Vfd2hlbgoKYGBgCntyIHJlY29kZSBUTk0yfQpteWRhdGEgPC0gbXlkYXRhICU+JSAKICAgIG11dGF0ZSgKICAgICAgICBUX3N0YWdlID0gY2FzZV93aGVuKAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIlQxIiwgeCA9IC4kVHN0YWdlKSA9PSBUUlVFIH4gIlQxIiwKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJUMiIsIHggPSAuJFRzdGFnZSkgPT0gVFJVRSB+ICJUMiIsCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiVDMiLCB4ID0gLiRUc3RhZ2UpID09IFRSVUUgfiAiVDMiLAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIlQ0IiwgeCA9IC4kVHN0YWdlKSA9PSBUUlVFIH4gIlQ0IiwKICAgICAgICAgICAgVFJVRSB+ICJUeCIKICAgICAgICApCiAgICApCmBgYAoKLS0tCgojIFJlY29kZSByZWd1bGFyIGV4cHJlc3Npb24gY2FzZV93aGVuCgpgYGAKe3J9Cm15ZGF0YSA8LSBteWRhdGEgJT4lIAogICAgbXV0YXRlKApUdW1vclBETDFncjEgPSBjYXNlX3doZW4oCiAgICAgICAgdF9wZGwxIDwgMSB+ICJrdWN1azEiLAogICAgICAgIHRfcGRsMSA+PSAxIH4gImJ1eXVrZXNpdDEiCiAgICApCiAgICApCmBgYAoKLS0tCgojIFIgTWFya2Rvd24gVGFuxLFtbGF5xLFjxLEgxLBzdGF0aXN0aWtsZXIgIAoKCmBgYAp7cn0KbGlicmFyeShzdW1tYXJ5dG9vbHMpCnZpZXcoZGZTdW1tYXJ5KGNvbG9uX3MpKQpgYGAKCgotLS0KCgpBIGJlZ2lubmVyIGtpdCBmb3IgI3JzdGF0cwpUaGUgTGFuZHNjYXBlIG9mIFIgUGFja2FnZXMgZm9yIEF1dG9tYXRlZCBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCmh0dHBzOi8vam91cm5hbC5yLXByb2plY3Qub3JnL2FyY2hpdmUvMjAxOS9SSi0yMDE5LTAzMy8KCgoKQGFydGljbGV7UkotMjAxOS0wMzMsCiAgYXV0aG9yID0ge01hdGV1c3ogU3RhbmlhayBhbmQgUHJ6ZW15c8WCYXcgQmllY2VrfSwKICB0aXRsZSA9IHt7VGhlIExhbmRzY2FwZSBvZiBSIFBhY2thZ2VzIGZvciBBdXRvbWF0ZWQgRXhwbG9yYXRvcnkgRGF0YQogICAgICAgICAgQW5hbHlzaXN9fSwKICB5ZWFyID0gezIwMTl9LAogIGpvdXJuYWwgPSB7e1RoZSBSIEpvdXJuYWx9fSwKICBkb2kgPSB7MTAuMzI2MTQvUkotMjAxOS0wMzN9LAogIHVybCA9IHtodHRwczovL2pvdXJuYWwuci1wcm9qZWN0Lm9yZy9hcmNoaXZlLzIwMTkvUkotMjAxOS0wMzMvaW5kZXguaHRtbH0KfQoKCgotLS0KCgojIyBUYWJsZSBPbmUgIAoKCmBgYAp7ciwgcmVzdWx0cz0nYXNpcyd9CiMgY2F0KG5hbWVzKG15ZGF0YSksIHNlcCA9ICIgKyBcbiIpCmxpYnJhcnkoYXJzZW5hbCkKdGFiMSA8LSB0YWJsZWJ5KH4gQ2luc2l5ZXQgKyAKWWFzICsgClR1bW9yWWVybGVzaW1pCiAgICAgICAgICAgICAgICAsCiAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhKQpzdW1tYXJ5KHRhYjEpCmBgYAoKLS0tCgojIyBUaGUgR3JhbW1hciBvZiBUYWJsZXMKCgpbdGFuZ3JhbTogVGhlIEdyYW1tYXIgb2YgVGFibGVzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGFuZ3JhbS8pCgpbQSBncmFtbWFyIG9mIHRhYmxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xlZXBlci90dHRhYmxlKQoKW0dyYW1tYXIgb2YgVGFibGVzP10oaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbGVlcGVyL2Y5Y2ZiZTZiZDE4NTc2Mzc2MmUxMjZhNGQ4ZDdjMjg2KQoKW0Vhc2lseSBnZW5lcmF0ZSBpbmZvcm1hdGlvbi1yaWNoLCBwdWJsaWNhdGlvbi1xdWFsaXR5IHRhYmxlcyBmcm9tIFJdKGh0dHBzOi8vZ3QucnN0dWRpby5jb20pCgoKLS0tCgojIyBLYXRlZ29yaWsgVmVyaWxlcgoKYGBgCntyfQpteWRhdGEgJT4lIAogIGphbml0b3I6OnRhYnlsKENhdGVnb3JpY2FsKSAlPiUKICBhZG9ybl9wY3RfZm9ybWF0dGluZyhyb3VuZGluZyA9ICdoYWxmIHVwJywKICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAxKSAlPiUKICBrbml0cjo6a2FibGUoKQpgYGAKCmBgYAp7ciBjcm9zc3RhYmxlfQpteWRhdGEgJT4lCiAgICBzdW1tYXJ5X2ZhY3Rvcmxpc3QoZGVwZW5kZW50ID0gZGVwZW5kZW50LCAKICAgICAgICAgICAgICAgICAgICAgICBleHBsYW5hdG9yeSA9IGV4cGxhbmF0b3J5LAogICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2NvbCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgcCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgYWRkX2RlcGVuZGVudF9sYWJlbCA9IFRSVUUpIC0+IHRhYmxlCmtuaXRyOjprYWJsZSh0YWJsZSwgcm93Lm5hbWVzID0gRkFMU0UsIGFsaWduID0gYygnbCcsICdsJywgJ3InLCAncicsICdyJykpCmBgYAoKLS0tCgojIyBLYXRlZ29yaWsgVmVyaWxlciBpw6dpbiBHcmFmaWtsZXIgIAoKYGBgCntyIGdnc3RhdHBsb3QsIGxheW91dD0nbC1wYWdlJ30KbXlkYXRhICU+JSAKICAgIGdnc3RhdHNwbG90OjpnZ2JhcnN0YXRzKGRhdGEgPSAuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFpbiA9IENhdGVnb3JpY2FsX3ZhcmlhYmxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZGl0aW9uID0gIGRlcGVuZGVudF92YXJpYWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQpgYGAKCi0tLQoKCiMjIENvbnRpbmlvdXMgVmFyaWFibGVzCgpgYGAKe3J9Cm15ZGF0YSAlPiUgCmptdjo6ZGVzY3JpcHRpdmVzKAogICAgZGF0YSA9IC4sCiAgICB2YXJzID0gYyh5YXMpLAogICAgaGlzdCA9IFRSVUUsCiAgICBkZW5zID0gVFJVRSwKICAgIGJveCA9IFRSVUUsCiAgICB2aW9saW4gPSBUUlVFLAogICAgZG90ID0gVFJVRSwKICAgIG1vZGUgPSBUUlVFLAogICAgc2QgPSBUUlVFLAogICAgdmFyaWFuY2UgPSBUUlVFLAogICAgc2tldyA9IFRSVUUsCiAgICBrdXJ0ID0gVFJVRSwKICAgIHF1YXJ0ID0gVFJVRSkKYGBgCgotLS0KCiMgUiBNYXJrZG93biDDtnJuZcSfaSDDh2FwcmF6IFRhYmxvbGFyICAKCmBgYAp7ciBjcm9zc3RhYmxlfQpsaWJyYXJ5KGZpbmFsZml0KQpteWRhdGEgJT4lCiAgICBzdW1tYXJ5X2ZhY3Rvcmxpc3QoZGVwZW5kZW50ID0gZGVwZW5kZW50LCAKICAgICAgICAgICAgICAgICAgICAgICBleHBsYW5hdG9yeSA9IGV4cGxhbmF0b3J5LAogICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbiA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfY29sID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBwID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBhZGRfZGVwZW5kZW50X2xhYmVsID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBuYV9pbmNsdWRlPUZBTFNFCiAgICAgICAgICAgICAgICAgICAgICAgIyBjYXRUZXN0ID0gY2F0VGVzdGZpc2hlcgogICAgICAgICAgICAgICAgICAgICAgICkgLT4gdGFibGUKa25pdHI6OmthYmxlKHRhYmxlLAogICAgICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICBhbGlnbiA9IGMoJ2wnLCAnbCcsICdyJywgJ3InLCAncicpKQpgYGAKCi0tLQoKIyBSIE1hcmtkb3duIMO2cm5lxJ9pIFNhxJ9rYWzEsW0gIAoKLSBEcmF3aW5nIFN1cnZpdmFsIEN1cnZlcyBVc2luZyBnZ3Bsb3QyICAKaHR0cHM6Ly9ycGtncy5kYXRhbm92aWEuY29tL3N1cnZtaW5lci9yZWZlcmVuY2UvZ2dzdXJ2cGxvdC5odG1sCgojIyBTYcSfa2FsxLFtIGnDp2luIHZlcml5aSBkw7x6ZW5sZW1lCgpgYGAKe3IgZGVmaW5lIHN1cnZpdmFsIHRpbWV9Cm15ZGF0YSRpbnQgPC0gbHVicmlkYXRlOjppbnRlcnZhbCgKICBsdWJyaWRhdGU6OnltZChteWRhdGEkQ2VycmFoaVRhcmloKSwKICBsdWJyaWRhdGU6OnltZChteWRhdGEkU29uVGFyaWgpCiAgKQpteWRhdGEkT3ZlcmFsbFRpbWUgPC0gbHVicmlkYXRlOjp0aW1lX2xlbmd0aChteWRhdGEkaW50LCAibW9udGgiKQpteWRhdGEkT3ZlcmFsbFRpbWUgPC0gcm91bmQobXlkYXRhJE92ZXJhbGxUaW1lLCBkaWdpdHMgPSAxKQpgYGAKCmBgYAp7cn0KIyMgUmVjb2RpbmcgbXlkYXRhJE91dGNvbWUgaW50byBteWRhdGEkT3V0Y29tZTIKbXlkYXRhJE91dGNvbWUyIDwtIHJlY29kZShteWRhdGEkT3V0Y29tZSwKICAgICAgICAgICAgICAgIkFsaXZlIiA9ICIwIiwKICAgICAgICAgICAgICAgIkRlYWQiID0gIjEiKQpteWRhdGEkT3V0Y29tZTIgPC0gYXMubnVtZXJpYyhteWRhdGEkT3V0Y29tZTIpCmBgYAoKLS0tCgojIyBLYXBsYW4tTWVpZXIKCmBgYAp7ciBLYXBsYW4tTWVpZXJ9Cm15ZGF0YSAlPiUKICBmaW5hbGZpdDo6c3Vydl9wbG90KGRlcGVuZGVudCwKICAgICAgICAgICAgICAgICAgICAgIGV4cGxhbmF0b3J5LAogICAgICAgICAgICAgICAgICAgICAgeGxhYj0nVGltZSAobW9udGhzKScsCiAgICAgICAgICAgICAgICAgICAgICBwdmFsPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSAnbm9uZScsCiAgICAgICAgICAgICAgICAgICAgICBicmVhay50aW1lLmJ5ID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICB4bGltID0gYygwLDYwKSwKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5sYWJzID0gYygnYScsJ2InKQopCmBgYAoKLS0tCgojIyBTYcSfa2FsxLFtIFRhYmxvbGFyxLEKCmBgYAp7cn0Ka21fZml0IDwtIHN1cnZmaXQoZGVwZW5kZW50IH4gZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEpCmttX2ZpdApgYGAKCmBgYAp7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShzdXJ2aXZhbCkKa20gPC0gd2l0aChteWRhdGEsIFN1cnYoT3ZlcmFsbFRpbWUsIE91dGNvbWUyKSkKIyBoZWFkKGttLDgwKQojIHBsb3Qoa20pCmBgYAoKYGBgCntyIDEtMy01LXlyfQpzdW1tYXJ5KGttX2ZpdCwgdGltZXMgPSBjKDEyLDM2LDYwKSkKYGBgCgotLS0KCiMjIFBhaXJ3aXNlIGNvbXBhcmlzb24KCmBgYAp7cn0Kc3Vydm1pbmVyOjpwYWlyd2lzZV9zdXJ2ZGlmZihmb3JtdWxhID0gU3Vydih0aW1lLCBPdXRjb21lKSB+IEdyb3VwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9ICJCSCIpCmBgYAoKLS0tCgojIyBNdWx0aXZhcmlhdGUgQW5hbHlzaXMgU3Vydml2YWwKCmBgYAp7ciBNdWx0aXZhcmlhdGUgQW5hbHlzaXMsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoZmluYWxmaXQpCmxpYnJhcnkoc3Vydml2YWwpCmV4cGxhbmF0b3J5TXVsdGl2YXJpYXRlIDwtIGV4cGxhbmF0b3J5S00KZGVwZW5kZW50TXVsdGl2YXJpYXRlIDwtIGRlcGVuZGVudEtNCm15ZGF0YSAlPiUKICBmaW5hbGZpdChkZXBlbmRlbnRNdWx0aXZhcmlhdGUsIGV4cGxhbmF0b3J5TXVsdGl2YXJpYXRlKSAtPiB0TXVsdGl2YXJpYXRlCmtuaXRyOjprYWJsZSh0TXVsdGl2YXJpYXRlLCByb3cubmFtZXM9RkFMU0UsIGFsaWduPWMoImwiLCAibCIsICJyIiwgInIiLCAiciIsICJyIikpCmBgYAoKLS0tCgojIGphbW92aQoKIyMgamFtb3ZpIHZlIFIgZW50ZWdyYXN5b251CgpbUmogRWRpdG9yIOKAkyBBbmFseXNlIHlvdXIgZGF0YSB3aXRoIFIgaW4gamFtb3ZpXShodHRwczovL2Jsb2cuamFtb3ZpLm9yZy8yMDE4LzA3LzMwL3JqLmh0bWwpCgoKCi0tLQoKIyMge2ptdn0gcGFrZXQga29kbGFyxLEKCltqYW1vdmkgc3ludGF4IG1vZGVdKGh0dHBzOi8vd3d3LmphbW92aS5vcmcvdXNlci1tYW51YWwuaHRtbCNzeW50YXgtbW9kZSkKCgoKCgoKLS0tCgojIEfDvG5jZWxsZW1lbGVyIG9sdW5jYSBrb2RsYXIgw6dhbMSxxZ9hY2FrIG3EsT8KCgotLS0KCiMjIFBha2V0IEvDvHTDvHBoYW5lbGVyaQoKLSBwYWNrcmF0IC8gcmVudgoKaHR0cHM6Ly9lbnZpcm9ubWVudHMucnN0dWRpby5jb20KCi0tLQoKIyMgRG9ja2VyCgotIGRvY2tlcgoKLS0tCgojIyMgVGhlIFJvY2tlciBQcm9qZWN0CgpEb2NrZXIgQ29udGFpbmVycyBmb3IgdGhlIFIgRW52aXJvbm1lbnQKCmBgYApkb2NrZXIgcnVuIC0tcm0gLXRpIHJvY2tlci9yLWJhc2UKYGBgCgpPciBnZXQgc3RhcnRlZCB3aXRoIGFuIFJTdHVkaW/CriBpbnN0YW5jZToKCmBgYApkb2NrZXIgcnVuIC1lIFBBU1NXT1JEPXlvdXJwYXNzd29yZCAtLXJtIC1wIDg3ODc6ODc4NyByb2NrZXIvcnN0dWRpbwpgYGAKCmFuZCBwb2ludCB5b3VyIGJyb3dzZXIgdG8gW2xvY2FsaG9zdDo4Nzg3XShsb2NhbGhvc3Q6ODc4NykKTG9nIGluIHdpdGggdXNlci9wYXNzd29yZCByc3R1ZGlvL3lvdXJwYXNzd29yZCAKCi0tLQoKCgpbTWFuYWdpbmcgY29udGFpbmVyc10oaHR0cHM6Ly93d3cucm9ja2VyLXByb2plY3Qub3JnL3VzZS9tYW5hZ2luZ19jb250YWluZXJzLykKCgotLS0KCiMjIFllbmkgUiBzw7xyw7xtbGVyaSAKCi0gUlN3aXRjaAoKaHR0cHM6Ly9ydWQuaXMvcnN3aXRjaC8KCi0gVXNpbmcgUlN3aXRjaAoKaHR0cHM6Ly9ydWQuaXMvcnN3aXRjaC9ndWlkZS8KCgohWzogc2NhbGUgMzAlXShodHRwczovL3J1ZC5pcy9yc3dpdGNoL2d1aWRlL21lbnUtaW5mby5wbmcpCgoKLS0tCgojIFllZGVrbGVtZXlpIG5hc8SxbCB5YXBhY2HEn8SxegoKIyMgUHJvamV5aSBkw7x6Z8O8biBvcmdhbml6ZSBlZGluCgotIHBkZgotIFIKLSBpbWFnZXMKLSBiaWIKCmBgYAp7ciBsb2FkIGxpYnJhcnl9CnNvdXJjZShmaWxlID0gaGVyZTo6aGVyZSgiUiIsICJsb2FkTGlicmFyeS5SIikpCmBgYAoKLS0tCgojIyBTYXZlIEZpbmFsIERhdGEKCmBgYAp7cn0Kc2F2ZWQgZGF0YSBhZnRlciBhbmFseXNpcyB0byBgbXlkYXRhLnhsc3hgLgoKc2F2ZS5pbWFnZShmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGFfd29ya19zcGFjZS5SRGF0YSIpKQoKcmVhZHI6OndyaXRlX3Jkcyh4ID0gbXlkYXRhLCBwYXRoID0gaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGFfYWZ0ZXJhbmFseXNpcy5yZHMiKSkKCnNhdmVSRFMob2JqZWN0ID0gbXlkYXRhLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGEucmRzIikpCgp3cml0ZXhsOjp3cml0ZV94bHN4KG15ZGF0YSwgaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGEueGxzeCIpKQoKcGFzdGUwKHJvd25hbWVzKGZpbGUuaW5mbyhoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YS54bHN4IikpKSwgIiA6ICIsIGZpbGUuaW5mbyhoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YS54bHN4IikpJGN0aW1lKQoKYGBgCgoKCgotLS0KCiMjIEdpdEh1YiBZZWRla2xlbWUKCmBgYHtyIGdpdGh1YiBwdXNoLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpDb21taXRNZXNzYWdlIDwtIHBhc3RlKCJ1cGRhdGVkIG9uICIsIFN5cy50aW1lKCksIHNlcCA9ICIiKQp3ZCA8LSBnZXR3ZCgpCmdpdENvbW1hbmQgPC0gcGFzdGUoImNkICIsIAogICAgICAgICAgICAgICAgICAgIHdkLAogICAgICAgICAgICAgICAgICAgICIgXG4gZ2l0IGFkZCAuIFxuIGdpdCBjb21taXQgLS1tZXNzYWdlICciLAogICAgICAgICAgICAgICAgICAgIENvbW1pdE1lc3NhZ2UsCiAgICAgICAgICAgICAgICAgICAgIicgXG4gZ2l0IHB1c2ggb3JpZ2luIG1hc3RlciBcbiIsCiAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIKICAgICAgICAgICAgICAgICAgICApCnN5c3RlbShjb21tYW5kID0gZ2l0Q29tbWFuZCwKICAgICAgIGludGVybiA9IFRSVUUKKQpgYGAKCi0tLQoKIyBIZXIgZMO2a8O8bWFuxLFuIHNvbnVuYSBrdWxsYW5kxLHEn8SxbsSxeiBrw7x0w7xwaGFuZWxlciBpw6dpbiBhdMSxZiB5YXpkxLFyYWJpbGlyc2luaXoKCmBgYAp7cn0KY2l0YXRpb24oKQpgYGAKCi0tLQoKIyMgTGlicmFyaWVzIFVzZWQgIAoKYGBge3IgbGlicmFyeSBjaXRhdGlvbiwgZWNobz1UUlVFfQpjaXRhdGlvbigpCmBgYAoKLS0tCgojIyBCdSBvdHVydW1hIHNwZXNpZmlrIGt1bGxhbsSxbGFuIHBha2V0bGVyICAKCmBgYHtyIGxpYnJhcnkgY2l0YXRpb24gYXMgcmVwb3J0LCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KcmVwb3J0OjpjaXRlX3BhY2thZ2VzKHNlc3Npb24gPSBzZXNzaW9uSW5mbygpKQpgYGAKCgotLS0KCiMjIFRlayB0ZWsgcGFrZXQgYXTEsWZsYXLEsQoKCmBgYAp7ciBsaWJyYXJ5IGNpdGF0aW9uc30KY2l0YXRpb24oInRpZHl2ZXJzZSIpCmNpdGF0aW9uKCJyZWFkeGwiKQpjaXRhdGlvbigiamFuaXRvciIpCmNpdGF0aW9uKCJyZXBvcnQiKQpjaXRhdGlvbigiZmluYWxmaXQiKQpjaXRhdGlvbigiZ2dzdGF0cGxvdCIpCmBgYAoKCi0tLQoKIyMgSmFtb3ZpIHZlIFIgacOnaW4gYXTEsWYgw7ZybmXEn2kKCi0gVGhlIGphbW92aSBwcm9qZWN0ICgyMDE5KS4gamFtb3ZpLiAoVmVyc2lvbiAwLjkpIFtDb21wdXRlciBTb2Z0d2FyZV0uIFJldHJpZXZlZCBmcm9tIGh0dHBzOi8vd3d3LmphbW92aS5vcmcuCgotIFIgQ29yZSBUZWFtICgyMDE4KS4gUjogQSBMYW5ndWFnZSBhbmQgZW52aW9ubWVudCBmb3Igc3RhdGlzdGljYWwgY29tcHV0aW5nLiBbQ29tcHV0ZXIgc29mdHdhcmVdLiBSZXRyaWV2ZWQgZnJvbSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8uCgotIEZveCwgSi4sICYgV2Vpc2JlcmcsIFMuICgyMDE4KS4gY2FyOiBDb21wYW5pb24gdG8gQXBwbGllZCBSZWdyZXNzaW9uLiBbUiBwYWNrYWdlXS4gUmV0cmlldmVkIGZyb20gaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvcGFja2FnZT1jYXIuCgoKCi0tLQoKIyBIZXIgZMO2a8O8bWFuxLFuIHNvbnVuYSBvdHVydW0gZGV0YXlsYXLEsW7EsXrEsSB5YXpkxLFyYWJpbGlyc2luaXogIAoKYGBgCntyIHNlc3Npb24gaW5mbywgZWNobz1UUlVFfQpzZXNzaW9uSW5mbygpCmBgYAoKLS0tCgojIyBTZXNzaW9uIEluZm8KCmBgYHtyIHNlc3Npb24gaW5mbywgZWNobz1UUlVFfQpzZXNzaW9uSW5mbygpCmBgYAoKLS0tCgojIFNvbnJha2kgS29udWxhcgoKLSBSU3R1ZGlvIGlsZSBHaXRIdWIga3VsbGFuxLFtxLEKLSAuLi4KCi0tLQoKIyDDlm5lcmlsZW4gS2F5bmFrbGFyCgotIFtSZXByb2R1Y2libGUgVGVtcGxhdGVzIGZvciBBbmFseXNpcyBhbmQgRGlzc2VtaW5hdGlvbl0oaHR0cHM6Ly93d3cuY291cnNlcmEub3JnL2xlYXJuL3JlcHJvZHVjaWJsZS10ZW1wbGF0ZXMtYW5hbHlzaXMvaG9tZS9pbmZvKQoKLSBbSGFwcHkgR2l0IGFuZCBHaXRIdWIgZm9yIHRoZSB1c2VSXShodHRwczovL2hhcHB5Z2l0d2l0aHIuY29tLykKCgoKCgotLS0KCiMgU3VudW0gTGlua2xlcmkKCmh0dHBzOi8vc2JhbGNpLmdpdGh1Yi5pby9NeVJDb2Rlc0ZvckRhdGFBbmFseXNpcy9SLU1hcmtkb3duLm5iLmh0bWwKaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvL015UkNvZGVzRm9yRGF0YUFuYWx5c2lzL1ItTWFya2Rvd24uaHRtbAoKaHR0cHM6Ly9mb3Jtcy5nbGUvVXFHSkJpQWpCOHVMUFJvbjgKCi0tLQoKIyBHZXJpIEJpbGRpcmltCgotIEdlcmkgYmlsZGlyaW0gacOnaW4gdMSxa2xhecSxbsSxejogX1tHZXJpIGJpbGRpcmltIGZvcm11XShodHRwczovL2dvby5nbC9mb3Jtcy9ZakdaNURIZ3RQbFIxUm5CMylfCgoKLS0tCgo8c2NyaXB0IGlkPSJkc3EtY291bnQtc2NyIiBzcmM9Ii8vaHR0cHMtc2JhbGNpLWdpdGh1Yi1pby5kaXNxdXMuY29tL2NvdW50LmpzIiBhc3luYz48L3NjcmlwdD4KCjxkaXYgaWQ9ImRpc3F1c190aHJlYWQiPjwvZGl2Pgo8c2NyaXB0PgoKLyoqCiogIFJFQ09NTUVOREVEIENPTkZJR1VSQVRJT04gVkFSSUFCTEVTOiBFRElUIEFORCBVTkNPTU1FTlQgVEhFIFNFQ1RJT04gQkVMT1cgVE8gSU5TRVJUIERZTkFNSUMgVkFMVUVTIEZST00gWU9VUiBQTEFURk9STSBPUiBDTVMuCiogIExFQVJOIFdIWSBERUZJTklORyBUSEVTRSBWQVJJQUJMRVMgSVMgSU1QT1JUQU5UOiBodHRwczovL2Rpc3F1cy5jb20vYWRtaW4vdW5pdmVyc2FsY29kZS8jY29uZmlndXJhdGlvbi12YXJpYWJsZXMqLwovKgp2YXIgZGlzcXVzX2NvbmZpZyA9IGZ1bmN0aW9uICgpIHsKdGhpcy5wYWdlLnVybCA9IFBBR0VfVVJMOyAgLy8gUmVwbGFjZSBQQUdFX1VSTCB3aXRoIHlvdXIgcGFnZSdzIGNhbm9uaWNhbCBVUkwgdmFyaWFibGUKdGhpcy5wYWdlLmlkZW50aWZpZXIgPSBQQUdFX0lERU5USUZJRVI7IC8vIFJlcGxhY2UgUEFHRV9JREVOVElGSUVSIHdpdGggeW91ciBwYWdlJ3MgdW5pcXVlIGlkZW50aWZpZXIgdmFyaWFibGUKfTsKKi8KKGZ1bmN0aW9uKCkgeyAvLyBET04nVCBFRElUIEJFTE9XIFRISVMgTElORQp2YXIgZCA9IGRvY3VtZW50LCBzID0gZC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsKcy5zcmMgPSAnaHR0cHM6Ly9odHRwcy1zYmFsY2ktZ2l0aHViLWlvLmRpc3F1cy5jb20vZW1iZWQuanMnOwpzLnNldEF0dHJpYnV0ZSgnZGF0YS10aW1lc3RhbXAnLCArbmV3IERhdGUoKSk7CihkLmhlYWQgfHwgZC5ib2R5KS5hcHBlbmRDaGlsZChzKTsKfSkoKTsKPC9zY3JpcHQ+Cjxub3NjcmlwdD5QbGVhc2UgZW5hYmxlIEphdmFTY3JpcHQgdG8gdmlldyB0aGUgPGEgaHJlZj0iaHR0cHM6Ly9kaXNxdXMuY29tLz9yZWZfbm9zY3JpcHQiPmNvbW1lbnRzIHBvd2VyZWQgYnkgRGlzcXVzLjwvYT48L25vc2NyaXB0PgoKLS0tCgojIMSwbGV0acWfaW0gIAoKQ29tcGxldGVkIG9uIGByIFN5cy5EYXRlKClgLiAgCgpTZXJkYXIgQmFsY2ksIE1ELCBQYXRob2xvZ2lzdCAgCmRyc2VyZGFyYmFsY2lAZ21haWwuY29tICAKCmh0dHBzOi8vcnB1YnMuY29tL3NiYWxjaS9DViAgIApodHRwczovL3NiYWxjaS5naXRodWIuaW8vICAKaHR0cHM6Ly9naXRodWIuY29tL3NiYWxjaSAgCmh0dHBzOi8vdHdpdHRlci5jb20vc2VyZGFyYmFsY2kKCgo=